package com.spa.application.service.member;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.spa.application.command.member.*;
import com.spa.application.dto.PageResult;
import com.spa.application.dto.member.*;
import com.spa.application.query.PageQuery;
import com.spa.application.query.member.*;
import com.spa.domain.entity.*;
import com.spa.domain.service.*;
import com.spa.infrastructure.enums.dict.SourceEnum;
import com.spa.infrastructure.enums.dict.base.RequestSourceEnum;
import com.spa.infrastructure.enums.dict.base.WhetherTypeEnum;
import com.spa.infrastructure.enums.dict.coupon.CouponTypeEnum;
import com.spa.infrastructure.exception.SpaException;
import com.spa.infrastructure.mapper.*;
import com.spa.infrastructure.repository.condition.CouponCondition;
import com.spa.infrastructure.repository.condition.FeedbackCondition;
import com.spa.infrastructure.repository.condition.MassagistEvaluateCondition;
import com.spa.infrastructure.repository.condition.UserAddressCondition;
import com.spa.infrastructure.repository.po.CouponExchangePO;
import com.spa.infrastructure.repository.po.CouponPO;
import com.spa.infrastructure.repository.po.UserAddressPO;
import com.spa.infrastructure.repository.po.FeedbackPO;
import com.spa.infrastructure.service.douyin.DouYinGoodLifeService;
import com.spa.infrastructure.service.douyin.result.PrepareResult;
import com.spa.infrastructure.service.douyin.result.ShopPoiQueryResult;
import com.spa.infrastructure.service.douyin.result.VerifyResult;
import com.spa.infrastructure.service.sms.GenerateSmsCodeKey;
import com.spa.infrastructure.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

@Service
@Slf4j
public class MemberMyApplicationService {

    @Resource
    private FeedbackService feedbackService;

    @Resource
    private AddressService addressService;

    @Resource
    private MassageService massageService;

    @Resource
    private UserTicketService userTicketService;

    @Resource
    private MassagistEvaluateService massagistEvaluateService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private GenerateSmsCodeKey generateSmsCodeKey;

    @Autowired
    private DouYinGoodLifeService douYinGoodLifeService;

    @Autowired
    private CouponService couponService;

    @Autowired
    private CouponExchangeService couponExchangeService;

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 用户端 新增我的 投诉/ 反馈意见
     *
     * @author: lig
     * @date: 2023/12/6
     */
    @Transactional
    public boolean addFeedBack(MemberFeedbackAddCommand command) {
        log.info("MemberFeedbackAddCommand{}", command);
        FeedbackPO po = FeedbackMapperStruct.INSTANCE.commandMember2Po(command);
        if(CollUtil.isNotEmpty(command.getImgList())){
            po.setImgs(Feedback.imgsListToImgs(command.getImgList()));
        }
        po.setUserId(SessionUtil.getUser().getExtUserId());
        return feedbackService.addInfo(po);
    }

    /**
     * 获取  我的反馈列表
     *
     * @author: lig
     * @date: 2024/1/11
     */
    public PageResult<MemberFeedbackDTO> pageFeedBack(MemberFeedbackQuery query){
        FeedbackCondition condition = FeedbackMapperStruct.INSTANCE.memberQuery2Condition(query);
        condition.setUserId(SessionUtil.getUser().getExtUserId());
        return FeedbackMapperStruct.INSTANCE.entity2MemberDto4Page(feedbackService.pageListInfo(condition));
    }

    /**
     * 添加用户地址
     *
     * @author: lig
     * @date: 2023/12/6
     */
    public MemberAddressesDTO addAddress(AddressesAddCommand command) {
        validate(command.getPhone(), command.getSmsCode());
        return UserAddressMapperStruct.INSTANCE.entity2Dto(addressService.addUserAddress(command,SessionUtil.getUser().getExtUserId()));
    }

    private void validate(String phone, String code) {
        Assert.isTrue(StringUtils.isNotEmpty(phone), "请确认手机号是否正常输入");
        Assert.isTrue(StringUtils.isNotEmpty(code), "请确验证码是否正常输入");
        String verifyKey = generateSmsCodeKey.generateSmsCodeKey(phone, RequestSourceEnum.Member_Address.getCode());
        String smsCaptcha = redisUtil.get(verifyKey);
        if (smsCaptcha == null) {
            throw new SpaException("短信验证码错误");
        }
        if (!code.equalsIgnoreCase(smsCaptcha)) {
            throw new SpaException("验证码错误");
        }
    }

    /**
     * 修改地址
     *
     * @author: lig
     * @date: 2023/12/6
     */
    public void editAddress(AddressesEditCommand command) {
        if (StringUtils.isNotEmpty(command.getSmsCode())) {
            validate(command.getPhone(), command.getSmsCode());
        }
        addressService.editAddress(BeanUtil.toBean(command, UserAddressPO.class));
    }

    /**
     * 删除地址
     *
     * @author: lig
     * @date: 2023-12-21
     */
    public void delAddress(AddressesDeleteCommand command) {
        addressService.delAddressById(command.getId());
    }

    /**
     * 获取地址分页
     *
     * @author: lig
     * @date: 2023/12/6
     */
    public PageResult<MemberAddressesDTO> page(MemberAddressesQuery query) {
        UserAddressCondition condition = UserAddressMapperStruct.INSTANCE.query2Condition(query);
        condition.setUserId(SessionUtil.getUser().getExtUserId());
        Page<UserAddress> dtoPage = addressService.page(condition);
        PageResult<MemberAddressesDTO> pageResult = UserAddressMapperStruct.INSTANCE.entity2MemberDto4Page(dtoPage);
        if(CollUtil.isNotEmpty(pageResult.getRecords())){
            List<MemberAddressesDTO> dtoAll = new ArrayList<>();
            List<MemberAddressesDTO> defaultDtoList = pageResult.getRecords().stream().filter(f ->f.getIsDefault() == WhetherTypeEnum.$0.getCode()).toList();
            //排序
            List<MemberAddressesDTO> notDefaultDtoList = pageResult.getRecords().stream().filter(f ->f.getIsDefault() != WhetherTypeEnum.$0.getCode()).toList();

            if(CollUtil.isNotEmpty(defaultDtoList)){
                dtoAll.addAll(defaultDtoList);
            }
            if(CollUtil.isNotEmpty(notDefaultDtoList)){
                dtoAll.addAll(notDefaultDtoList);
            }
            pageResult.setRecords(dtoAll);
        }
        return pageResult;
    }

    /**
     * 设置默认地址
     *
     * @author: lig
     * @date: 2023/12/6
     */
    public void editDefault(AddressesEditDefaultCommand command) {
        addressService.editDefault(SessionUtil.getUser().getExtUserId(),command.getId());
    }

    /**
     * 优惠券列表  获取服务项目的 我的可用优惠券列表
     *
     * @author: lig
     * @date: 2023/12/15
     */
    public List<MemberTicketDTO> couponUsableMyList(MemberCouponQuery query) {
        Long serviceId = query.getServiceId();
        Integer serviceCount = query.getServiceCount();
        MassageServiceEntity serviceEntity = massageService.infoById(serviceId);

        List<MemberTicketDTO> listTicketDto = UserTicketMapperStruct.INSTANCE.entity2MemberDto4List(userTicketService.listByUserId(SessionUtil.getUser().getExtUserId()));
        if (CollUtil.isNotEmpty(listTicketDto)) {
            listTicketDto.stream().forEach(a -> {
                //计算优惠券是否可用
                BigDecimal couponPriceDec = getCouponPriceDec(a, serviceEntity.getDiscountPrice(), serviceCount);
                if (couponPriceDec.compareTo(BigDecimal.ZERO) > 0) {
                    //可用
                    a.setIsUsable(WhetherTypeEnum.$0.getCode());
                } else {
                    a.setIsUsable(WhetherTypeEnum.$1.getCode());
                }
                a.setTypeName(CouponTypeEnum.byCode(a.getType()).getDesc());

            });
            return listTicketDto;
        }
        return new ArrayList<>();
    }

    /**
     * 获取优惠券金额
     *
     * @author: lig
     * @date: 2023/12/14
     */
    public BigDecimal getCouponPriceDec(MemberTicketDTO userTicketRef, Integer servicePrice, Integer serviceCount) {
        if (BeanUtil.isNotEmpty(userTicketRef)) {
            if (userTicketRef.getDiscountType() == 1) {
                //满减
                BigDecimal thresholdDec = CurrencyUtils.fenToYuan(Convert.toInt(userTicketRef.getOverflow(),0));
                //订单服务总金额
                BigDecimal serviceTotalPriceDec = CurrencyUtils.fenToYuan(OrderUtils.calcOrderServiceTotal(servicePrice, serviceCount));
                if (serviceTotalPriceDec.compareTo(thresholdDec) > -1) {
                    //可用优惠券
                    return CurrencyUtils.fenToYuan(Convert.toInt(userTicketRef.getRmb(),0));
                }
            }
        }
        return BigDecimal.ZERO;
    }

    public List<MemberTicketDTO> listByUserId() {
        List<MemberTicketDTO> listTicketDto = UserTicketMapperStruct.INSTANCE.entity2MemberDto4List(userTicketService.listByUserId(SessionUtil.getUser().getExtUserId()));
        return listTicketDto;
    }

    public boolean addMyEvaluate(MassagistEvaluateAddCommand command){
        if(StpUtil.isLogin()){
            Assert.isFalse(massagistEvaluateService.verifyEvaluate(command.getOrderId(),SessionUtil.getUser().getUserId()),"已经对订单评价过了");
        }
        return massagistEvaluateService.memberAddMy(command);
    }

    /**
     * 获取我的技师评论列表
     *
     * @author: lig
     * @date: 2024-01-08
     */
    public PageResult<MemberMassagistEvaluateDTO> pageMassagistEvaluate(MemberMassagistEvaluateQuery query) {
        MassagistEvaluateCondition condition = MassagistEvaluateMapperStruct.INSTANCE.queryMember2Condition(query);
        condition.setIsDel(WhetherTypeEnum.$0.getCode());
        Page<MassagistEvaluate> pageEntity = massagistEvaluateService.pageListInfo(condition);
        pageEntity.getRecords().forEach(a ->{
            a.setUserName("匿名用户");
        });
        return MassagistEvaluateMapperStruct.INSTANCE.entity2Dto4Page(pageEntity);
    }

    public ScanCodeDTO scanCode(String url) throws MalformedURLException, UnsupportedEncodingException {
        String longUrl = UrlUtil.resolveShortUrl(url);
        Map<String, String>  map = splitQuery(new URL(longUrl));
        ScanCodeDTO scanCodeDTO = new ScanCodeDTO();
        scanCodeDTO.setEncryptedData(map.get("object_id"));
        return scanCodeDTO;
    }

    @Transactional
    public void exchange(ExchangeCommand command) throws JsonProcessingException {
        String lockKey = "exchange：lock:" + SessionUtil.getUser().getExtUserId();
        String id = UUID.fastUUID().toString(true);
        try {
            boolean lockFlag = redisUtil.getLock(lockKey, id);
            if (!lockFlag) {
                throw new SpaException("操作频繁！");
            }
            log.info("ExchangeCommand : {}", command);
            PrepareResult prepareResult = null;
            //验券准备
            if (StringUtils.isNotEmpty(command.getCode())) {
                prepareResult = douYinGoodLifeService.prepareByCode(command.getCode());
            } else {
                prepareResult = douYinGoodLifeService.prepareByEncryptedData(command.getEncryptedData());
            }
            if (prepareResult.getData().getError_code() != 0) {
                throw new SpaException("兑换失败");
            }
            long userId = SessionUtil.getUser().getExtUserId();
            UserInfo userInfo = userInfoService.userInfoById(userId);
            //验券 todo  后期通过平台创建商品优化
            ShopPoiQueryResult shopPoiQueryResult = douYinGoodLifeService.queryShop();
            List<String> poiIds = shopPoiQueryResult.getData().getPois().stream().map(ShopPoiQueryResult.PoiRoot::getPoi)
                    .map(ShopPoiQueryResult.Poi::getPoi_id).toList();
            VerifyResult verifyResult = null;
            for (String poiId : poiIds) {
                verifyResult = douYinGoodLifeService.verify(prepareResult, poiId);
                if (verifyResult.getData().getError_code() == 0) {
                    break;
                }
            }
            if (verifyResult.getData().getError_code() != 0) {
                throw new SpaException("兑换失败");
            }
            List<VerifyResult.Verify> verifies = verifyResult.getData().getVerify_results();
            if (!verifies.isEmpty()) {
                VerifyResult.Verify verify = verifies.get(0);
                if (verify.getResult() != 0) {
                    throw new SpaException("兑换失败");
                }
            }
            List<PrepareResult.Certificate> certificates = prepareResult.getData().getCertificates();
            if (!certificates.isEmpty()) {
                PrepareResult.Certificate certificate = certificates.get(0);
                PrepareResult.Sku sku = certificate.getSku();
                PrepareResult.Amount amount = certificate.getAmount();
                MassageServiceEntity massageServiceEntity = massageService.infoById(Convert.toLong(sku.getThird_sku_id()));
                //成功后 保存兑换记录 生成团购券
                CouponPO po = new CouponPO();
                po.setServiceId(massageServiceEntity.getId());
                po.setName(sku.getTitle());
                po.setSource(SourceEnum.$1.getCode());
                po.setPrice(sku.getMarket_price());
                po.setUserId(userId);
                po.setUsername(userInfo.getName());
                po.setPhone(userInfo.getPhone());
                po.setCreateTime(new Date());
                po.setServicePrice(massageServiceEntity.getDiscountPrice());
                couponService.insertCoupon(po);

                CouponExchangePO couponExchangePO = new CouponExchangePO();
                couponExchangePO.setCode(prepareResult.getData().getOrder_id());
                couponExchangePO.setSource(SourceEnum.$1.getCode());
                couponExchangePO.setUsername(userInfo.getName());
                couponExchangePO.setPhone(userInfo.getPhone());
                couponExchangePO.setServiceName(sku.getTitle());
                couponExchangePO.setPrice(massageServiceEntity.getDiscountPrice());
                couponExchangePO.setGroupPrice(amount.getPay_amount());
                couponExchangePO.setPayTime(new Date(certificate.getStart_time() * 1000));
                couponExchangePO.setDestroyTime(new Date());
                couponExchangePO.setCouponId(po.getId());
                couponExchangePO.setCreateTime(new Date());
                List<VerifyResult.Verify> verifies0 = verifyResult.getData().getVerify_results();
                if (!verifies0.isEmpty()) {
                    VerifyResult.Verify verify = verifies0.get(0);
                    couponExchangePO.setVerifyId(verify.getVerify_id());
                    couponExchangePO.setCertificateId(verify.getCertificate_id());
                }
                couponExchangeService.insertCoupon(couponExchangePO);
            }
        } finally {
            redisUtil.releaseLock(lockKey, id);
        }
    }

    public PageResult<CouponDTO> page(PageQuery query) {
        CouponCondition condition = CouponMapperStruct.INSTANCE.query2Condition(query);
        condition.setUserId(SessionUtil.getUser().getExtUserId());
        condition.setStatusAscAndCreateTimeDesc(true);
        return CouponMapperStruct.INSTANCE.entity2Dto4Page(couponService.page(condition));
    }

    private Map<String, String> splitQuery(URL url) throws UnsupportedEncodingException {
        Map<String, String> queryPairs = new HashMap<>();
        String query = url.getQuery();
        if (query == null) {
            return queryPairs;
        }
        String[] pairs = query.split("&");
        for (String pair : pairs) {
            int idx = pair.indexOf("=");
            queryPairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
        }
        return queryPairs;
    }
}
